package game.util;

import game.games.rpg.SaveGame;

import java.io.File;
import java.io.IOException;
import java.io.PrintStream;

import javax.swing.JOptionPane;

public class Logger
{
    private static MultipliedPrintStream out = new MultipliedPrintStream();
    static
    {
        out.add(System.out);
        // logfile
        try
        {
            File logFolder = new File(SaveGame.getSaveDir(), "logs");
            if ((logFolder.exists() == false && logFolder.mkdirs() == false) || logFolder.isDirectory() == false)
            {
                showExceptionError(new IOException("logFolder " + logFolder + " is unusable (isfile:" + logFolder.isFile()));
            }
            else
            {
                File outFile = new File(logFolder, System.currentTimeMillis() + ".out");
                out.add(new PrintStream(outFile));
                trace("!!! LOGGING TO FILE: ", outFile.getAbsolutePath());
            }
        }
        catch (IOException e)
        {
            showExceptionError(e);
        }
    }
    
    public enum Level
    {
        TRACE, DEBUG, INFO, WARN, ERROR, FATAL;
        public boolean log(Level l)
        {
            boolean log = false;
            switch (this)
            {
                case TRACE:
                {
                    log = true;
                    break;
                }
                case DEBUG:
                {
                    log = (l == DEBUG || l == INFO || l == WARN || l == ERROR || l == FATAL);
                    break;
                }
                case INFO:
                {
                    log = (l == INFO || l == WARN || l == ERROR || l == FATAL);
                    break;
                }
                case WARN:
                {
                    log = (l == WARN || l == ERROR || l == FATAL);
                    break;
                }
                case ERROR:
                {
                    log = (l == ERROR || l == FATAL);
                    break;
                }
                case FATAL:
                {
                    log = (l == FATAL);
                    break;
                }
            }
            return log;
        }
    }
    
    private static Level LEVEL = Level.TRACE;
    
    public static Level getLevel()
    {
        if (LEVEL == null)
        {
            LEVEL = Level.TRACE;
        }
        return LEVEL;
    }
    
    public static void trace(Object ... objs)
    {
        if (getLevel().log(Level.TRACE))
        {
            println("TRACE> " + getMessage(objs));
        }
    }
    
    public static void debug(Object ... objs)
    {
        if (getLevel().log(Level.DEBUG))
        {
            println("DEBUG> " + getMessage(objs));
        }
    }
    
    public static void info(Object ... objs)
    {
        if (getLevel().log(Level.INFO))
        {
            println("INFO>  " + getMessage(objs));
        }
    }
    
    public static void warn(Object ... objs)
    {
        if (getLevel().log(Level.WARN))
        {
            println("WARN>  " + getMessage(objs));
        }
    }
    
    public static void error(Object ... objs)
    {
        if (getLevel().log(Level.ERROR))
        {
            println("ERROR> " + getMessage(objs));
        }
    }
    
    public static void fatal(Object ... objs)
    {
        if (getLevel().log(Level.FATAL))
        {
            println("FATAL> " + getMessage(objs));
        }
    }
    
    private static String getMessage(Object ... objs)
    {
        StringBuilder message = new StringBuilder();
        if (objs.length > 0)
        {
            for (Object o : objs)
            {
                if (o instanceof String)
                {
                    message.append((String)o);
                }
                else
                {
                    if (o instanceof Throwable)
                    {
                        message.append(((Throwable)o).getLocalizedMessage());
                    }
                    message.append(Util.toString(o));
                }
            }
        }
        return message.toString();
    }
    
    private static void println(String string)
    {
        out.println(string);
    }
    
    public static void showError(String error)
    {
        JOptionPane.showMessageDialog(null, error, "ERROR", JOptionPane.ERROR_MESSAGE);
    }
    
    public static void showExceptionError(Throwable ex)
    {
        error(ex);
        showError(Util.toString(ex));
    }
}
